﻿namespace MSpecTests.WhoCanHelpMe.Web.Controllers
{
    #region Using Directives

    using System.Security.Authentication;
    using System.Web.Mvc;

    using global::WhoCanHelpMe.Domain.Contracts.Tasks;
    using global::WhoCanHelpMe.Web.Controllers.User;
    using global::WhoCanHelpMe.Web.Controllers.User.Mappers.Contracts;

    using Machine.Specifications;

    using Rhino.Mocks;

    #endregion

    public abstract class specification_for_user_controller
    {
        protected static ILoginPageViewModelMapper login_page_view_model_mapper;

        protected static IIdentityTasks identity_tasks;

        protected static UserController sut;

        Establish context = () =>
            {
                identity_tasks = MockRepository.GenerateStub<IIdentityTasks>();

                login_page_view_model_mapper = MockRepository.GenerateStub<ILoginPageViewModelMapper>();
            };

        protected static void CreateSut()
        {
            sut = new UserController(identity_tasks, login_page_view_model_mapper);
        }
    }

    [Subject(typeof(UserController))]
    public class when_the_user_controller_is_asked_for_the_default_view_and_the_user_is_logged_in : specification_for_user_controller
    {
        static ActionResult result;

        Establish context = () =>
            {
                identity_tasks.Stub(i => i.IsSignedIn()).Return(true);

                CreateSut();
            };

        Because b = () => result = sut.Index();

        It should_ask_the_identity_tasks_if_the_user_is_signed_in =
            () => identity_tasks.AssertWasCalled(i => i.IsSignedIn());

        It should_redirect_to_home = () => 
        { 
            result.IsARedirectToARouteAnd().ControllerName().ShouldEqual("Home");
            result.IsARedirectToARouteAnd().ActionName().ShouldEqual("Index");
        };
    }

    [Subject(typeof(UserController))]
    public class when_the_user_controller_is_asked_for_the_default_view_and_the_user_is_not_logged_in : specification_for_user_controller
    {
        static ActionResult result;

        Establish context = () =>
        {
            identity_tasks.Stub(i => i.IsSignedIn()).Return(false);

            CreateSut();
        };

        Because b = () => result = sut.Index();

        It should_ask_the_identity_tasks_if_the_user_is_signed_in =
            () => identity_tasks.AssertWasCalled(i => i.IsSignedIn());

        It should_redirect_to_the_login_action = 
            () => result.IsARedirectToARouteAnd().ActionName().ShouldEqual("Login");
    }

    [Subject(typeof(UserController))]
    public class when_the_user_controller_is_asked_for_the_login_view_and_the_user_is_logged_in : specification_for_user_controller
    {
        static ActionResult result;

        Establish context = () =>
        {
            identity_tasks.Stub(i => i.IsSignedIn()).Return(true);

            CreateSut();
        };

        Because b = () => result = sut.Login(string.Empty);

        It should_ask_the_identity_tasks_if_the_user_is_signed_in =
            () => identity_tasks.AssertWasCalled(i => i.IsSignedIn());

        It should_redirect_to_home = () =>
        {
            result.IsARedirectToARouteAnd().ControllerName().ShouldEqual("Home");
            result.IsARedirectToARouteAnd().ActionName().ShouldEqual("Index");
        };
    }

    [Subject(typeof(UserController))]
    public class when_the_user_controller_is_asked_for_the_login_view_and_the_user_is_not_logged_in : specification_for_user_controller
    {
        static ActionResult result;

        private static object the_view_model;

        Establish context = () =>
        {
            identity_tasks.Stub(i => i.IsSignedIn()).Return(false);

            CreateSut();
        };

        Because b = () => result = sut.Login(string.Empty);

        It should_ask_the_identity_tasks_if_the_user_is_signed_in =
            () => identity_tasks.AssertWasCalled(i => i.IsSignedIn());

        It should_ask_the_login_page_view_model_mapper_to_map_the_view_model =
            () => login_page_view_model_mapper.AssertWasCalled(
                      m => m.MapFrom(
                               null,
                               string.Empty));

        It should_return_the_default_view = () => result.IsAViewAnd().ViewName.ShouldBeEmpty();

        It should_pass_the_view_model_to_the_view =
            () => result.IsAViewAnd().ViewData.Model.ShouldEqual(the_view_model);
    }

    [Subject(typeof(UserController))]
    public class when_the_user_controller_is_asked_to_logout : specification_for_user_controller
    {
        static ActionResult result;

        Establish context = () =>
            {
                identity_tasks.Stub(i => i.IsSignedIn()).Return(true);

                CreateSut();
            };

        Because b = () => result = sut.SignOut();

        It should_ask_the_identity_tasks_to_log_the_current_user_out =
            () => identity_tasks.AssertWasCalled(i => i.SignOut());

        It should_redirect_to_home = () =>
        {
            result.IsARedirectToARouteAnd().ControllerName().ShouldEqual("Home");
            result.IsARedirectToARouteAnd().ActionName().ShouldEqual("Index");
        };
    }

    [Subject(typeof(UserController))]
    public class when_the_user_controller_is_asked_to_authenticate_with_a_return_url_and_authentication_is_successful : specification_for_user_controller
    {
        static ActionResult result;

        static string the_user_id;

        static string the_return_url;

        Establish context = () =>
        {
            the_user_id = "open id";

            the_return_url = "return url";

            CreateSut();
        };

        Because b = () => result = sut.Authenticate(the_user_id, the_return_url);

        It should_ask_the_identity_tasks_to_authenticate_the_user =
            () => identity_tasks.AssertWasCalled(i => i.Authenticate(the_user_id));

        It should_redirect_to_the_return_url = 
            () => result.IsARedirectAnd().Url.ShouldEqual(the_return_url);
    }

    [Subject(typeof(UserController))]
    public class when_the_user_controller_is_asked_to_authenticate_without_a_return_url_and_authentication_is_successful : specification_for_user_controller
    {
        static ActionResult result;

        static string the_user_id;

        static string the_return_url;

        Establish context = () =>
        {
            the_user_id = "open id";

            the_return_url = string.Empty;

            CreateSut();
        };

        Because b = () => result = sut.Authenticate(the_user_id, the_return_url);

        It should_ask_the_identity_tasks_to_authenticate_the_user =
            () => identity_tasks.AssertWasCalled(i => i.Authenticate(the_user_id));

        It should_redirect_to_home = () =>
        {
            result.IsARedirectToARouteAnd().ControllerName().ShouldEqual("Home");
            result.IsARedirectToARouteAnd().ActionName().ShouldEqual("Index");
        };
    }

    [Subject(typeof(UserController))]
    public class when_the_user_controller_is_asked_to_authenticate_and_authentication_is_unsuccessful : specification_for_user_controller
    {
        static ActionResult result;

        static string the_user_id;

        static string the_return_url;

        Establish context = () =>
        {
            the_user_id = "open id";

            the_return_url = "return url";

            identity_tasks.Stub(i => i.Authenticate(the_user_id)).Throw(new AuthenticationException());

            CreateSut();
        };

        Because b = () => result = sut.Authenticate(the_user_id, the_return_url);

        It should_ask_the_identity_tasks_to_authenticate_the_user =
            () => identity_tasks.AssertWasCalled(i => i.Authenticate(the_user_id));

        It should_redirect_to_the_login_view =
            () => result.IsARedirectToARouteAnd().ActionName().ShouldEqual("Login");
    }

}
